package com.jandar;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

import com.jandar.generator.IdGenerator;
import com.jandar.generator.impl.UUIDGenerator;
import com.jandar.logging.LoggerFactory;
import com.jandar.parser.BaseParser;
import com.jandar.table.TableHander;
import com.jandar.table.config.Table;
import com.jandar.table.config.Tables;
import com.jandar.util.DateUtils;
import com.jandar.util.ExceptionUtils;
import com.jandar.util.SecurityUtils;

/**
 * 资源类。
 * 
 * @author pqj
 * @version 2009-7-9
 */
public class Resources {

	public static final String CONFIG = "/resources.properties";

	public static final String TABLE_CONFIG = "/table-config.xml";

	public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";

	public static final String IN_FOLDER_KEY = "infolder";

	public static final String OUT_FOLDER_KEY = "outfolder";

	public static final String ERR_FOLDER_KEY = "errfolder";

	public static final String DIRVER_KEY = "driver";

	public static final String URL_KEY = "url";

	public static final String START_TIME_KEY = "startTime";

	public static final String PERIOD_KEY = "period";

	public static final String FILE_TYPE_KEY = "fileType";

	public static final String SEQUENCE_KEY = "sequence";

	public static final String OVERRIDE_FILE_KEY = "overrideFile";

	public static final String OVERRIDE_PREFIX_KEY = "overridePrefix";

	public static final String MANY_SHEETS_KEY = "manySheets";

	public static final String BOOL_TYPE_KEY = "boolType";

	public static final String BOOL_TRUE_KEY = "boolTrue";

	public static final String BOOL_FALSE_KEY = "boolFalse";

	public static final String DATABASETYPE_KEY = "dataBaseType";

	public static final String ID_GENERATOR_KEY = "idGenerator";

	public static final String TXT_SEPARATOR_KEY = "txtSeparator";

	public static final String HASEMPTYFIELD_KEY = "hasEmptyField";

	public static final String EXCHANGETABLE_KEY = "exchangeTable";

	public static final String DATATITLE_KEY = "dataTitle";

	public static final String TIMETASK_KEY = "timeTask";

	public static final String URLENCRYPT_KEY = "urlEncrypt";

	private static Resources INSTANCE = new Resources();

	/** 导入文件夹 */
	private File infolder = null;

	/** 导出文件夹 */
	private File outfolder = null;

	/** 错误文件夹 */
	private File errfolder = null;

	/** 数据库驱动名 */
	private String driver = null;

	/** 数据库连接URL */
	private String url = null;

	/** 定时器启动时间 */
	private Date startTime = null;

	/** 定时器间隔时间 */
	private long period = 0;

	/** 导入文件类型 */
	private String[] fileType = null;

	/** 移动文件时候是否覆盖 */
	private boolean overrideFile = false;

	/** 覆盖文件命名前缀 */
	private String overridePrefix = null;

	/** EXCEL文件是否包含多个sheet */
	private boolean manySheets = false;

	/** 布尔型导入值 True */
	private List<String> boolTrue = null;

	/** 布尔型导入值 False */
	private List<String> boolFalse = null;

	/** 数据库表配置 key: 表名 value: Table */
	private Map<String, Table> tableCfgMap = null;

	private Tables tables = null;

	/** 数据库类型 */
	private DataBaseType dataBaseType = null;

	/** 文本文件字段分隔符 */
	private String txtSeparator = null;

	/** 录入文件中ID字段是否留有空缺位置 */
	private boolean hasEmptyField = false;

	/** 交换表名 */
	private String exchangeTable = null;

	/** 数据文件是否含有标题 */
	private boolean dataTitle = false;

	/** 定时器任务 */
	private String timeTask = null;

	/** 是否对JDBC URL 进行加密 */
	private boolean urlEncrypt = false;
	
	/** 主键生成策略 */
	private IdGenerator idGenerator = null;

	private Resources() {
		load();
	}

	/**
	 * 重新加载一次配置文件。
	 */
	public void reload() {
		load();
	}

	/**
	 * 对外提供重新加载接口。
	 * 
	 * @param in 文件输入流
	 */
	public void load() {
		InputStream in = Resources.class.getResourceAsStream(CONFIG);
		// 日志文件配置
		LoggerFactory.reloadConfig(in);
		in = Resources.class.getResourceAsStream(CONFIG);

		try {
			Properties config = new Properties();
			config.load(in);

			// 文件夹配置
			infolder = new File(config.getProperty(IN_FOLDER_KEY));
			outfolder = new File(config.getProperty(OUT_FOLDER_KEY));
			errfolder = new File(config.getProperty(ERR_FOLDER_KEY));
			driver = config.getProperty(DIRVER_KEY);
			urlEncrypt = Boolean.parseBoolean(config.getProperty(URLENCRYPT_KEY));
			if (urlEncrypt) {
				url = config.getProperty(URL_KEY);
				url = SecurityUtils.base64Decoder(url);
			} else {
				url = config.getProperty(URL_KEY);
			}

			String startTimeStr = config.getProperty(START_TIME_KEY);
			if (isEmpty(startTimeStr)) {
				// 默认使用当前时间，定时器会即立即执行。
				startTime = new Date();
			} else {
				try {
					startTime = (new SimpleDateFormat(DEFAULT_DATE_PATTERN)).parse(startTimeStr);
				} catch (ParseException e) {
					// 格式不对使用当前时间
					startTime = new Date();
				}
			}

			String periodStr = config.getProperty(PERIOD_KEY);
			if (isEmpty(periodStr)) {
				// 默认间隔时间是10秒
				period = 10000;
			} else {
				try {
					period = Long.parseLong(periodStr);
				} catch (Exception e) {
					period = 10000;
				}
			}
			String fileTypeStr = config.getProperty(FILE_TYPE_KEY);
			if (isEmpty(fileTypeStr)) {
				// 默认使用.XLS文件
				fileType = new String[] { BaseParser.XLS_TYPE };
			} else {
				fileType = fileTypeStr.toLowerCase().split(",");
			}

			String overrideFileStr = config.getProperty(OVERRIDE_FILE_KEY);
			if (isEmpty(overrideFileStr)) {
				// 默认是会覆盖的
				overrideFile = true;
			} else {
				overrideFile = Boolean.parseBoolean(overrideFileStr);
			}

			overridePrefix = config.getProperty(OVERRIDE_PREFIX_KEY);
			if (isEmpty(overridePrefix)) {
				overridePrefix = "copy ";
			}

			String manySheetsStr = config.getProperty(MANY_SHEETS_KEY);
			if (isEmpty(manySheetsStr)) {
				// 默认只解析第一个sheet
				manySheets = false;
			} else {
				manySheets = Boolean.parseBoolean(manySheetsStr);
			}

			// 布尔型导入值 TRUE
			String boolTrueStr = config.getProperty(BOOL_TRUE_KEY);
			if (!isEmpty(boolTrueStr)) {
				boolTrue = Arrays.asList(boolTrueStr.split(","));
			}
			// 布尔型导入值 FALSE
			String boolFalseStr = config.getProperty(BOOL_FALSE_KEY);
			if (!isEmpty(boolFalseStr)) {
				boolFalse = Arrays.asList(boolFalseStr.split(","));
			}

			// 数据库类型
			String dataBaseTypeStr = config.getProperty(DATABASETYPE_KEY);
			if (isEmpty(dataBaseTypeStr)) {
				throw new NullPointerException("dataBaseType is null.");
			}
			this.dataBaseType = DataBaseType.valueOf(dataBaseTypeStr);

			// 文本文件分隔符
			txtSeparator = config.getProperty(TXT_SEPARATOR_KEY);
			if (isEmpty(txtSeparator)) {
				txtSeparator = "\t";
			}

			// 录入文件中ID字段是否留有空缺位置
			hasEmptyField = Boolean.valueOf(config.getProperty(HASEMPTYFIELD_KEY));

			// 交换表名
			exchangeTable = config.getProperty(EXCHANGETABLE_KEY);
			if (isEmpty(exchangeTable)) {
				exchangeTable = "exchangestat";
			}
			
			// 主键生成器
			String idGeneratorName = config.getProperty(ID_GENERATOR_KEY);
			if (isEmpty(idGeneratorName)) {
				idGenerator = new UUIDGenerator();
			} else {
				idGenerator = (IdGenerator) Class.forName(idGeneratorName).newInstance();
			}

			// 数据文件是否含有标题
			dataTitle = Boolean.valueOf(config.getProperty(DATATITLE_KEY));

			// 定时器任务
			timeTask = config.getProperty(TIMETASK_KEY);
			if (isEmpty(timeTask)) {
				timeTask = "com.jandar.task.DefaultTimerTask";
			}

			// 初始化数据库表配置
			InputStream tabCfgInput = Resources.class.getResourceAsStream(TABLE_CONFIG);
			if (tabCfgInput == null) {
				throw new Exception("table-config.xml is not found.");
			}
			initTableConfig(tabCfgInput);
		} catch (Exception e) {
			ExceptionUtils.error(e);
		}
	}

	private void initTableConfig(InputStream in) throws ParserConfigurationException, SAXException,
			IOException {
		SAXParserFactory parserFactory = SAXParserFactory.newInstance();
		parserFactory.setValidating(false);
		SAXParser parser = parserFactory.newSAXParser();
		TableHander hander = new TableHander();
		parser.parse(in, hander);
		this.tables = hander.getTables();
		this.tableCfgMap = hander.getTableCfgMap();
	}

	private boolean isEmpty(String s) {
		return (s == null || "".equals(s)) ? true : false;
	}

	public static Resources getInstance() {
		return INSTANCE;
	}

	public File getInfolder() {
		return infolder;
	}

	public File getOutfolder() {
		return outfolder;
	}

	public File getErrfolder() {
		return errfolder;
	}

	public String getDriver() {
		return driver;
	}

	public String getUrl() {
		return url;
	}

	public Date getStartTime() {
		return startTime;
	}

	public String getStartTimeStr() {
		return DateUtils.format(DEFAULT_DATE_PATTERN, startTime);
	}

	public long getPeriod() {
		return period;
	}

	public String[] getFileType() {
		return fileType;
	}

	public boolean isOverrideFile() {
		return overrideFile;
	}

	public String getOverridePrefix() {
		return overridePrefix;
	}

	public boolean isManySheets() {
		return manySheets;
	}

	public void setInfolder(File infolder) {
		this.infolder = infolder;
	}

	public void setOutfolder(File outfolder) {
		this.outfolder = outfolder;
	}

	public void setErrfolder(File errfolder) {
		this.errfolder = errfolder;
	}

	public void setDriver(String driver) {
		this.driver = driver;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}

	public void setPeriod(long period) {
		this.period = period;
	}

	public void setFileType(String[] fileType) {
		this.fileType = fileType;
	}

	public void setOverrideFile(boolean overrideFile) {
		this.overrideFile = overrideFile;
	}

	public void setOverridePrefix(String overridePrefix) {
		this.overridePrefix = overridePrefix;
	}

	public void setManySheets(boolean manySheets) {
		this.manySheets = manySheets;
	}

	public List<String> getBoolFalse() {
		return boolFalse;
	}

	public void setBoolFalse(List<String> boolFalse) {
		this.boolFalse = boolFalse;
	}

	public List<String> getBoolTrue() {
		return boolTrue;
	}

	public void setBoolTrue(List<String> boolTrue) {
		this.boolTrue = boolTrue;
	}

	public Tables getTables() {
		return tables;
	}

	public void setTables(Tables tables) {
		this.tables = tables;
	}

	public Map<String, Table> getTableCfgMap() {
		return tableCfgMap;
	}

	public void setTableCfgMap(Map<String, Table> tableCfgMap) {
		this.tableCfgMap = tableCfgMap;
	}

	public DataBaseType getDataBaseType() {
		return dataBaseType;
	}

	public void setDataBaseType(DataBaseType dataBaseType) {
		this.dataBaseType = dataBaseType;
	}

	public String getTxtSeparator() {
		return txtSeparator;
	}

	public void setTxtSeparator(String txtSeparator) {
		this.txtSeparator = txtSeparator;
	}

	public boolean isHasEmptyField() {
		return hasEmptyField;
	}

	public void setHasEmptyField(boolean hasEmptyField) {
		this.hasEmptyField = hasEmptyField;
	}

	public String getExchangeTable() {
		return exchangeTable;
	}

	public void setExchangeTable(String exchangeTable) {
		this.exchangeTable = exchangeTable;
	}

	public boolean isDataTitle() {
		return dataTitle;
	}

	public void setDataTitle(boolean dataTitle) {
		this.dataTitle = dataTitle;
	}

	public String getTimeTask() {
		return timeTask;
	}

	public void setTimeTask(String timeTask) {
		this.timeTask = timeTask;
	}

	public boolean isUrlEncrypt() {
		return urlEncrypt;
	}

	public void setUrlEncrypt(boolean urlEncrypt) {
		this.urlEncrypt = urlEncrypt;
	}

	public IdGenerator getIdGenerator() {
		return idGenerator;
	}

	public void setIdGenerator(IdGenerator idGenerator) {
		this.idGenerator = idGenerator;
	}

}
